package com.dji.system.core;

import java.io.File;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.dji.bean.Autowired;
import com.dji.bean.Compoment;
import com.dji.bean.InitializingBean;
import com.dji.common.utils.ClassUtils;
import com.dji.common.utils.SystemUtils;

public class Scanner {
	private final static Logger log = LoggerFactory.getLogger(Scanner.class);
	private Map<String, Object> beanMap;

	/**
	 * 扫描组件并且注入属性 【依照属性类型注入】
	 * 
	 * @throws Exception
	 */
	public void scanAndInvoke() throws Exception {
		String projectPath = SystemUtils.getClassPath();
		List<File> fileList = getAllFileByPath(new File(projectPath));
		beanMap = getCompments(fileList);
		invoke(beanMap);
		log.debug("扫描完毕,共加载" + beanMap.keySet().size() + "个组件");
	}

	/**
	 * 获取指定路径下的所有文件 [目录不能太深否则内存溢出]
	 * 
	 * @return
	 */
	private List<File> getAllFileByPath(File file) {
		List<File> result = new LinkedList<File>();
		if (file.isFile()) {
			result.add(file);
		} else if (file.isDirectory()) {
			for (File item : file.listFiles()) {
				result.addAll(getAllFileByPath(item));
			}
		}
		return result;
	}

	/**
	 * 将组件实例化
	 * 
	 * @return
	 */
	private Map<String, Object> getCompments(List<File> fileList) {
		Map<String, Object> compoment = new HashMap<String, Object>();
		Object obj = null;
		Class<?> classInfo = null;
		String fileName = null;
		for (File item : fileList) {
			fileName = item.getName();
			if (item.isFile() && (fileName.endsWith(ClassUtils.CLASS_EXTENSION)
					|| fileName.endsWith(ClassUtils.JAVA_EXTENSION))) {
				try {
					classInfo = ClassUtils.getClass(item);
					if (classInfo.isAnnotation()) {
						continue;
					} else {
						Annotation[] aa = classInfo.getAnnotationsByType(Compoment.class);
						if (aa.length > 0) {
							obj = ClassUtils.newInstance(item);
							compoment.put(obj.getClass().getName(), obj);
							log.debug("实例化对象" + obj.getClass().getName());
						} else {
							// log.debug("忽略对象" +
							// ClassUtils.getPackageInfo(item));
						}
					}
				} catch (Exception e) {
					try {
						log.debug("实例化对象失败" + ClassUtils.getPackageInfo(item));
					} catch (Exception e1) {
						e.printStackTrace();
						e1.printStackTrace();
					}
				}
			}
		}
		return compoment;
	}

	/**
	 * 给所有填写了注解的组件字段赋值
	 * 
	 * @param beanMap
	 * @throws Exception
	 */
	private void invoke(Map<String, Object> beanMap) throws Exception {
		Iterator<Entry<String, Object>> beanIterator = beanMap.entrySet().iterator();
		Object bean = null;
		Annotation[] fieldAnnotations = null;
		InitializingBean initializingBean;
		while (beanIterator.hasNext()) {
			@SuppressWarnings("rawtypes")
			Map.Entry item = (Map.Entry) beanIterator.next();
			bean = item.getValue();
			Field[] fields = bean.getClass().getDeclaredFields();
			for (Field field : fields) {
				fieldAnnotations = field.getAnnotationsByType(Autowired.class);
				if (fieldAnnotations.length > 0) {
					// 这个字段使用了按照类型注入
					if (beanMap.containsKey(field.getType().getName())) {
						ClassUtils.setFieldValue(bean, field.getName(), beanMap.get(field.getType().getName()));
					} else {
						try {
							ClassUtils.setFieldValue(bean, field.getName(),ClassUtils.newInstance(fieldAnnotations[0].toString()));
						} catch (Exception e) {
							log.error(bean.getClass().getName() + "." + field.getType().getName(), e);
						}
					}
				}
				 
			}
			if (bean instanceof InitializingBean) {
				initializingBean = (InitializingBean) bean;
				initializingBean.afterProPertiesSet();
			}
		}
	}

	/**
	 * 获取bean对象
	 * 
	 * @param className
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public <T> T getBean(T className) {
		return (T) beanMap.get(className.getClass().getName());
	}

}
